using System.Linq;
using UniversalAdmin.Application.Common;
using UniversalAdmin.Application.Dtos.Menu;
using UniversalAdmin.Application.Services.Interfaces;
using UniversalAdmin.Domain.Entities.App;
using UniversalAdmin.Domain.Repositories;

namespace UniversalAdmin.Application.Services.Implementations;

/// <summary>
/// 菜单服务实现类
/// </summary>
public class MenuService : IMenuService
{
    private readonly IRepositories<Menu> _menuRepository;

    public MenuService(IRepositories<Menu> menuRepository)
    {
        _menuRepository = menuRepository;
    }

    /// <summary>
    /// 获取所有菜单列表
    /// </summary>
    /// <returns>菜单DTO集合</returns>
    public async Task<IEnumerable<MenuDto>> GetAllMenusAsync()
    {
        var menus = await _menuRepository.GetAllAsync();

        return menus.Where(m => !m.IsDeleted).Select(menu => new MenuDto
        {
            Id = menu.Id,
            Name = menu.Name,
            Path = menu.Path,
            Icon = menu.Icon,
            ParentId = menu.ParentId,
            Sort = menu.Sort,
            Code = menu.Code,
            IsActive = menu.IsActive,
            IsDeleted = menu.IsDeleted,
            CreatedAt = menu.CreatedAt,
            UpdatedAt = menu.UpdatedAt,
            CreatedBy = menu.CreatedBy,
            UpdatedBy = menu.UpdatedBy
        }).OrderBy(m => m.Sort);
    }

    /// <summary>
    /// 获取菜单树形结构
    /// </summary>
    /// <returns>菜单树形结构</returns>
    public async Task<IEnumerable<MenuDto>> GetMenuTreeAsync()
    {
        var allMenus = await GetAllMenusAsync();
        var menuList = allMenus.ToList();

        // 获取根菜单（没有父级的菜单）
        var rootMenus = menuList.Where(m => m.ParentId == null).ToList();

        // 为每个根菜单构建子菜单树
        foreach (var rootMenu in rootMenus)
        {
            BuildMenuTree(rootMenu, menuList);
        }

        return rootMenus.OrderBy(m => m.Sort);
    }

    /// <summary>
    /// 根据ID获取菜单详情
    /// </summary>
    /// <param name="menuId">菜单ID</param>
    /// <returns>菜单DTO或错误结果</returns>
    public async Task<dynamic> GetMenuByIdAsync(Guid menuId)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null || menu.IsDeleted)
        {
            return ApiResult.Fail(404, "菜单不存在");
        }

        // 获取父级菜单名称
        string? parentName = null;
        if (menu.ParentId.HasValue)
        {
            var parentMenu = await _menuRepository.GetByIdAsync(menu.ParentId.Value);
            parentName = parentMenu?.Name;
        }

        var menuDto = new MenuDto
        {
            Id = menu.Id,
            Name = menu.Name,
            Path = menu.Path,
            Icon = menu.Icon,
            ParentId = menu.ParentId,
            ParentName = parentName,
            Sort = menu.Sort,
            Code = menu.Code,
            IsActive = menu.IsActive,
            IsDeleted = menu.IsDeleted,
            CreatedAt = menu.CreatedAt,
            UpdatedAt = menu.UpdatedAt,
            CreatedBy = menu.CreatedBy,
            UpdatedBy = menu.UpdatedBy
        };

        return ApiResult.Success(menuDto, "获取菜单成功");
    }

    /// <summary>
    /// 创建新菜单
    /// </summary>
    /// <param name="createMenuDto">菜单创建参数</param>
    /// <returns>操作结果</returns>
    public async Task<dynamic> CreateMenuAsync(CreateMenuDto createMenuDto)
    {
        // 检查菜单名称是否已存在
        var existingMenu = _menuRepository.Table.FirstOrDefault(m => m.Name == createMenuDto.Name && !m.IsDeleted);
        if (existingMenu != null)
        {
            return ApiResult.Fail(400, "菜单名称已存在");
        }

        // 验证父级菜单是否存在（如果提供了父级ID）
        if (createMenuDto.ParentId.HasValue)
        {
            var parentMenu = await _menuRepository.GetByIdAsync(createMenuDto.ParentId.Value);
            if (parentMenu == null || parentMenu.IsDeleted)
            {
                return ApiResult.Fail(400, "父级菜单不存在");
            }
            if (!parentMenu.IsActive)
            {
                return ApiResult.Fail(400, "父级菜单已禁用");
            }
        }

        var menu = new Menu
        {
            Id = Guid.NewGuid(),
            Name = createMenuDto.Name,
            Path = createMenuDto.Path,
            Icon = createMenuDto.Icon,
            ParentId = createMenuDto.ParentId,
            Sort = createMenuDto.Sort,
            Code = createMenuDto.Code ?? Guid.NewGuid().ToString("N")[..8], // 如果未提供编码则自动生成
            // 系统自动管理的字段
            IsActive = true,        // 默认启用
            IsDeleted = false,      // 默认未删除
            CreatedAt = DateTime.UtcNow,    // 创建时间（系统自动设置，不可修改）
            UpdatedAt = DateTime.UtcNow,    // 更新时间（系统自动设置，不可修改）
            CreatedBy = Guid.Empty,         // 创建者ID（系统自动设置，不可修改）TODO: 应从当前用户上下文获取
            UpdatedBy = Guid.Empty          // 更新者ID（系统自动设置，不可修改）TODO: 应从当前用户上下文获取
        };

        await _menuRepository.CreateAsync(menu);

        return ApiResult.Success(new { MenuId = menu.Id }, "菜单创建成功");
    }

    /// <summary>
    /// 更新菜单信息
    /// </summary>
    /// <param name="menuId">菜单ID</param>
    /// <param name="updateMenuDto">菜单更新参数</param>
    /// <returns>操作结果</returns>
    public async Task<dynamic> UpdateMenuAsync(Guid menuId, UpdateMenuDto updateMenuDto)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null || menu.IsDeleted)
        {
            return ApiResult.Fail(404, "菜单不存在");
        }

        // 检查菜单名称是否与其他菜单重复
        var existingMenu = _menuRepository.Table.FirstOrDefault(m => m.Name == updateMenuDto.Name && m.Id != menuId && !m.IsDeleted);
        if (existingMenu != null)
        {
            return ApiResult.Fail(400, "菜单名称已存在");
        }

        // 验证父级菜单（如果提供了父级ID）
        if (updateMenuDto.ParentId.HasValue)
        {
            // 检查是否试图将菜单设置为自己的子菜单
            if (updateMenuDto.ParentId.Value == menuId)
            {
                return ApiResult.Fail(400, "不能将菜单设置为自己的子菜单");
            }

            var parentMenu = await _menuRepository.GetByIdAsync(updateMenuDto.ParentId.Value);
            if (parentMenu == null || parentMenu.IsDeleted)
            {
                return ApiResult.Fail(400, "父级菜单不存在");
            }

            // 检查是否会形成循环引用
            if (await IsCircularReferenceAsync(menuId, updateMenuDto.ParentId.Value))
            {
                return ApiResult.Fail(400, "不能形成循环引用");
            }
        }

        // 只更新用户可以修改的字段
        menu.Name = updateMenuDto.Name;
        menu.Path = updateMenuDto.Path;
        menu.Icon = updateMenuDto.Icon;
        menu.ParentId = updateMenuDto.ParentId;
        menu.Sort = updateMenuDto.Sort;
        menu.IsActive = updateMenuDto.IsActive;  // 虽然有专门的启用/禁用接口，但这里也允许直接设置

        // 系统自动管理的字段
        menu.UpdatedAt = DateTime.UtcNow;        // 更新时间（系统自动设置，不可修改）
        menu.UpdatedBy = Guid.Empty;             // 更新者ID（系统自动设置，不可修改）TODO: 应从当前用户上下文获取
        // 注意：CreatedAt 和 CreatedBy 不允许修改

        await _menuRepository.UpdateAsync(menu);

        // 返回更新后的菜单数据和成功消息
        var updatedMenuDto = new MenuDto
        {
            Id = menu.Id,
            Name = menu.Name,
            Path = menu.Path,
            Icon = menu.Icon,
            ParentId = menu.ParentId,
            Sort = menu.Sort,
            Code = menu.Code,
            IsActive = menu.IsActive,
            IsDeleted = menu.IsDeleted,
            CreatedAt = menu.CreatedAt,
            UpdatedAt = menu.UpdatedAt,
            CreatedBy = menu.CreatedBy,
            UpdatedBy = menu.UpdatedBy
        };

        return ApiResult.Success(updatedMenuDto, "菜单更新成功");
    }

    /// <summary>
    /// 删除菜单（软删除）
    /// </summary>
    /// <param name="menuId">菜单ID</param>
    /// <returns>操作结果</returns>
    public async Task<dynamic> DeleteMenuAsync(Guid menuId)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null || menu.IsDeleted)
        {
            return ApiResult.Fail(404, "菜单不存在");
        }

        // 检查是否有子菜单
        var childMenus = _menuRepository.Table.Where(m => m.ParentId == menuId && !m.IsDeleted).ToList();
        if (childMenus.Any())
        {
            return ApiResult.Fail(400, "该菜单下还有子菜单，请先删除子菜单");
        }

        // 软删除：系统自动管理的状态变更
        menu.IsDeleted = true;           // 标记为已删除
        menu.IsActive = false;           // 同时禁用
        menu.UpdatedAt = DateTime.UtcNow;        // 更新时间（系统自动设置，不可修改）
        menu.UpdatedBy = Guid.Empty;             // 更新者ID（系统自动设置，不可修改）TODO: 应从当前用户上下文获取删除操作者

        await _menuRepository.UpdateAsync(menu);

        return ApiResult.Success(new { MenuId = menu.Id, MenuName = menu.Name }, "菜单删除成功");
    }

    /// <summary>
    /// 启用菜单
    /// </summary>
    /// <param name="menuId">菜单ID</param>
    /// <returns>操作结果</returns>
    public async Task<dynamic> EnableMenuAsync(Guid menuId)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null || menu.IsDeleted)
        {
            return ApiResult.Fail(404, "菜单不存在");
        }

        if (menu.IsActive)
        {
            return ApiResult.Fail(400, "菜单已处于启用状态");
        }

        // 系统自动管理的状态变更
        menu.IsActive = true;                    // 启用菜单
        menu.UpdatedAt = DateTime.UtcNow;        // 更新时间（系统自动设置，不可修改）
        menu.UpdatedBy = Guid.Empty;             // 更新者ID（系统自动设置，不可修改）TODO: 应从当前用户上下文获取操作者
        await _menuRepository.UpdateAsync(menu);

        return ApiResult.Success(new { MenuId = menu.Id, MenuName = menu.Name, IsActive = menu.IsActive }, "菜单已启用");
    }

    /// <summary>
    /// 禁用菜单
    /// </summary>
    /// <param name="menuId">菜单ID</param>
    /// <returns>操作结果</returns>
    public async Task<dynamic> DisableMenuAsync(Guid menuId)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null || menu.IsDeleted)
        {
            return ApiResult.Fail(404, "菜单不存在");
        }

        if (!menu.IsActive)
        {
            return ApiResult.Fail(400, "菜单已处于禁用状态");
        }

        // 系统自动管理的状态变更
        menu.IsActive = false;                   // 禁用菜单
        menu.UpdatedAt = DateTime.UtcNow;        // 更新时间（系统自动设置，不可修改）
        menu.UpdatedBy = Guid.Empty;             // 更新者ID（系统自动设置，不可修改）TODO: 应从当前用户上下文获取操作者
        await _menuRepository.UpdateAsync(menu);

        return ApiResult.Success(new { MenuId = menu.Id, MenuName = menu.Name, IsActive = menu.IsActive }, "菜单已禁用");
    }

    /// <summary>
    /// 获取子菜单列表
    /// </summary>
    /// <param name="parentId">父级菜单ID</param>
    /// <returns>子菜单集合</returns>
    public async Task<IEnumerable<MenuDto>> GetChildMenusAsync(Guid parentId)
    {
        var allMenus = await GetAllMenusAsync();
        return allMenus.Where(m => m.ParentId == parentId).OrderBy(m => m.Sort);
    }

    /// <summary>
    /// 移动菜单位置
    /// </summary>
    /// <param name="menuId">菜单ID</param>
    /// <param name="newParentId">新的父级菜单ID</param>
    /// <param name="newSort">新的排序号</param>
    /// <returns>操作结果</returns>
    public async Task<dynamic> MoveMenuAsync(Guid menuId, Guid? newParentId, int newSort)
    {
        var menu = await _menuRepository.GetByIdAsync(menuId);
        if (menu == null || menu.IsDeleted)
        {
            return ApiResult.Fail(404, "菜单不存在");
        }

        // 验证新的父级菜单
        if (newParentId.HasValue)
        {
            if (newParentId.Value == menuId)
            {
                return ApiResult.Fail(400, "不能将菜单移动到自己下面");
            }

            var newParentMenu = await _menuRepository.GetByIdAsync(newParentId.Value);
            if (newParentMenu == null || newParentMenu.IsDeleted)
            {
                return ApiResult.Fail(400, "目标父级菜单不存在");
            }

            // 检查是否会形成循环引用
            if (await IsCircularReferenceAsync(menuId, newParentId.Value))
            {
                return ApiResult.Fail(400, "已在此菜单下");
            }
        }

        // 更新菜单位置
        menu.ParentId = newParentId;
        menu.Sort = newSort;

        // 系统自动管理的字段
        menu.UpdatedAt = DateTime.UtcNow;        // 更新时间（系统自动设置，不可修改）
        menu.UpdatedBy = Guid.Empty;             // 更新者ID（系统自动设置，不可修改）TODO: 应从当前用户上下文获取操作者

        await _menuRepository.UpdateAsync(menu);

        return ApiResult.Success(new
        {
            MenuId = menu.Id,
            MenuName = menu.Name,
            NewParentId = menu.ParentId,
            NewSort = menu.Sort
        }, "菜单移动成功");
    }

    #region 私有方法

    /// <summary>
    /// 构建菜单树
    /// </summary>
    /// <param name="parentMenu">父级菜单</param>
    /// <param name="allMenus">所有菜单列表</param>
    private void BuildMenuTree(MenuDto parentMenu, List<MenuDto> allMenus)
    {
        var children = allMenus.Where(m => m.ParentId == parentMenu.Id).OrderBy(m => m.Sort).ToList();
        parentMenu.Children = children;

        foreach (var child in children)
        {
            BuildMenuTree(child, allMenus);
        }
    }

    /// <summary>
    /// 检查是否会形成循环引用
    /// </summary>
    /// <param name="menuId">当前菜单ID</param>
    /// <param name="targetParentId">目标父级菜单ID</param>
    /// <returns>是否会形成循环引用</returns>
    private async Task<bool> IsCircularReferenceAsync(Guid menuId, Guid targetParentId)
    {
        var currentParent = await _menuRepository.GetByIdAsync(targetParentId);

        while (currentParent != null && !currentParent.IsDeleted)
        {
            if (currentParent.Id == menuId)
            {
                return true; // 形成循环引用
            }

            if (currentParent.ParentId.HasValue)
            {
                currentParent = await _menuRepository.GetByIdAsync(currentParent.ParentId.Value);
            }
            else
            {
                break;
            }
        }

        return false;
    }

    #endregion
}
